package request

import (
	"errors"
	"fmt"
	"github.com/go-playground/validator/v10"
	"github.com/labstack/echo/v4"
	"github.com/rs/zerolog"
	"net/http"
	"reflect"
	"ruoyi-go-echo-ddd/internal/infrastructure/http/response"
	"ruoyi-go-echo-ddd/internal/infrastructure/utils"
	"strings"
)

// 自定义验证器结构体
type CustomValidator struct {
	Validator *validator.Validate
}

// 自定义验证
func (cv *CustomValidator) Validate(i any) error {
	/* if err := cv.Validator.Struct(i); err != nil {
		if validationErrs, ok := err.(validator.ValidationErrors); ok {
			errors := make(map[string]string)
			for _, e := range validationErrs {
				errors[e.Field()] = fmt.Sprintf(
					"Field validation failed: %s (tag: %s)",
					e.Field(), e.Tag())
			}
			zerolog.DefaultContextLogger.Error().Err(err).Msg("验证失败")
		}
		//echo.NewHTTPError(http.StatusInternalServerError, err.Error())
		return err
	} */
	return cv.Validator.Struct(i)
}

// HandlerValidatorErr 处理验证错误
func HandlerValidatorErr(c echo.Context, err error) {
	if err == nil {
		return
	}

	logger := zerolog.DefaultContextLogger

	var validationErrs validator.ValidationErrors

	if errors.As(err, &validationErrs) {
		errorsList := make([]string, 0)
		//errors := make(map[string]string)
		for _, fieldErr := range validationErrs {
			// 获取字段名（去除JSON标签前缀）
			//fieldName := strings.ToLower(fieldErr.Field())

			//errors[fieldName] = handlerErrorMessage(fieldErr)
			errorsList = append(errorsList, handlerErrorMessage(fieldErr))
		}
		logger.Error().Any("validationErrs", errorsList).Msg("验证错误")
		response.NewRespCodeMsg(c, http.StatusInternalServerError, strings.Join(errorsList, ";"))
		return
	}
}

// handlerErrorMessage 处理错误信息
func handlerErrorMessage(fieldErr validator.FieldError) string {
	fieldName := utils.PascalCaseToCamel(fieldErr.Field())
	switch fieldErr.Tag() {
	case "required":
		return fmt.Sprintf("%s是必填字段", fieldName)
	case "email":
		return fmt.Sprintf("%s必须是有效的邮箱地址", fieldName)
	case "url":
		return fmt.Sprintf("%s必须是有效的URL地址", fieldName)
	case "min":
		if fieldErr.Kind().String() == "string" {
			return fmt.Sprintf("%s长度不能少于%s个字符", fieldName, fieldErr.Param())
		}
		return fmt.Sprintf("%s值不能小于%s", fieldName, fieldErr.Param())
	case "max":
		if fieldErr.Kind() == reflect.String {
			return fmt.Sprintf("%s长度不能超过%s个字符", fieldName, fieldErr.Param())
		}
		return fmt.Sprintf("%s值不能大于%s", fieldName, fieldErr.Param())
	case "alphanum":
		return fmt.Sprintf("%s只能包含字母和数字", fieldName)
	case "oneof":
		return fmt.Sprintf("%s只能是以下值之一: %s", fieldName, strings.Replace(fieldErr.Param(), " ", ", ", -1))
	default:
		return fmt.Sprintf("Validation failed on '%s' tag", fieldErr.Tag())
	}
}

// 获取字段名（优先使用JSON标签）
func getFieldName(fe validator.FieldError) string {
	// 获取值的反射类型
	val := reflect.ValueOf(fe.Value())
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	// 检查是否是可寻址的值（避免 panic）
	if !val.IsValid() {
		return strings.ToLower(fe.Field())
	}

	// 获取值的类型
	t := val.Type()

	// 尝试获取结构体字段信息
	field, found := t.FieldByName(fe.Field())
	if !found {
		return strings.ToLower(fe.Field())
	}

	// 获取 JSON 标签
	jsonTag := field.Tag.Get("json")
	if jsonTag == "" {
		return strings.ToLower(fe.Field())
	}
	// 处理逗号分隔的标签
	if commaIdx := strings.Index(jsonTag, ","); commaIdx != -1 {
		return jsonTag[:commaIdx]
	}
	return jsonTag
}
